package com.by.component.contract;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.by.component.contract.dto.*;
import com.by.component.contract.mapper.ContractSignRecordMapper;
import com.by.component.contract.support.ContractSupport;
import com.by.component.staticresources.StaticResourcesService;
import com.by.datasource.transaction.AfterCommitExecutor;
import com.by.datasource.utils.PageUtil;
import com.by.mqsender.support.ByMqSupport;
import com.by.toolkit.consts.MqTagConst;
import com.by.toolkit.enums.FlagEnum;
import com.by.toolkit.model.PageReq;
import com.by.toolkit.model.PageResp;
import com.by.toolkit.utils.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import static com.by.toolkit.utils.ExceptionUtil.nullError;
import static com.by.toolkit.utils.ExceptionUtil.trueError;

@Slf4j
@DubboService
public class ContractSignRecordServiceImpl implements ContractSignRecordService {

    @Resource
    private ContractSignRecordMapper contractSignRecordMapper;

    @Resource
    private ByMqSupport byMqSupport;

    @Resource
    private ContractSupport contractSupport;

    @Resource
    private StaticResourcesService staticResourcesService;

    @Override
    public void distributeContract(DistributeContractSDTO dto) {
        ContractSignRecord contractSignRecord = ContractSignRecord.builder()
                .userId(dto.getUserId())
                .contractInfoId(dto.getContractInfoId())
                .sceneType(dto.getSceneType())
                .sceneId(dto.getSceneId())
                .build();

        try {
            contractSignRecordMapper.insert(contractSignRecord);
        } catch (Exception e) {
            if (ExceptionUtil.uqIndexError(e)) {
                return;
            }
            throw e;
        }
        AfterCommitExecutor.execute(() -> {
            byMqSupport.sendAsync(Map.of(
                    "sceneType", dto.getSceneType(),
                    "sceneId", dto.getSceneId(),
                    "contractSignRecordId", contractSignRecord.getId()
            ), MqTagConst.DISTRIBUTE_CONTRACT_SUCCESS_AFTER);
        });
    }

    @Override
    public void signContract(SignContractSDTO dto) {
        log.info("[ContractSignRecordServiceImpl][signContract] dto = {}", dto);
        try {
            Long userId = dto.getUserId();
            Long contractInfoId = dto.getContractInfoId();
            Integer sceneType = dto.getSceneType();
            Long sceneId = dto.getSceneId();
            Long htmlContractFileId = dto.getContractFileId();
            Long contractSignRecordId = dto.getContractSignRecordId();

            ContractSignRecord contractSignRecord = contractSignRecordMapper.selectOne(new LambdaQueryWrapper<ContractSignRecord>()
                    .select(ContractSignRecord::getId,
                            ContractSignRecord::getSignFlag)
                    .eq(ContractSignRecord::getId, contractSignRecordId));

            nullError(contractSignRecord, "合同信息不存在");
            trueError(FlagEnum.yes(contractSignRecord.getSignFlag()), "合同已签署，无法再次签署");

            contractSignRecord.setContractFileId(htmlContractFileId);
            contractSignRecord.setSignFlag(FlagEnum.YES.getCode());
            contractSignRecord.setSignTime(LocalDateTime.now());
            contractSignRecordMapper.updateById(contractSignRecord);

            AfterCommitExecutor.execute(() -> {
                byMqSupport.sendAsync(Map.of(
                        "contractSignRecordId", contractSignRecord.getId(),
                        "sceneType", sceneType,
                        "sceneId", sceneId
                ), MqTagConst.CONTRACT_SIGN_SUCCESS_AFTER);
            });
        } catch (Exception e) {
            if (ExceptionUtil.uqIndexError(e)) {
                return;
            }
            throw e;
        }
    }

    @Override
    public List<ContractSignRecord4DeliverSDTO> contractSignRecord4Deliver(Long userId) {
        return contractSignRecordMapper.queryContractSignRecord4Deliver(userId);
    }

    @Override
    public PageResp<ContractSignRecord4PageSDTO> queryPage(PageReq<ContractSignRecord4PageSDTO> req) {
        return PageUtil.toPageResp(contractSignRecordMapper.queryPage(Page.of(req.getPageIdx(), req.getPageSize()), req.getCondition()));
    }

    @Override
    public void uploadContractFile(Long contractSignRecordId) {
        log.info("[ContractSignRecordServiceImpl][uploadContractFile] contractSignRecordId = {}", contractSignRecordId);
        ContractSignRecord contractSignRecord = contractSignRecordMapper.selectOne(new LambdaQueryWrapper<ContractSignRecord>()
                .select(ContractSignRecord::getId,
                        ContractSignRecord::getContractFileId)
                .eq(ContractSignRecord::getId, contractSignRecordId));
        nullError(contractSignRecord, "合同记录不存在");

        Long htmlContractFileId = contractSignRecord.getContractFileId();
        String HtmlContractUrl = staticResourcesService.resourcesUrl(htmlContractFileId);
        Long pdfContractFileId = contractSupport.htmlToPdf(HtmlContractUrl);
        nullError(pdfContractFileId, "合同PDF处理失败");

        contractSignRecordMapper.updateById(ContractSignRecord.builder()
                .id(contractSignRecordId)
                .contractFileId(pdfContractFileId)
                .build());
    }

    @Override
    public void removeContractSignRecord(DistributeContractSDTO dto) {
        contractSignRecordMapper.delete(new LambdaQueryWrapper<ContractSignRecord>()
                .eq(ContractSignRecord::getUserId, dto.getUserId())
                .eq(ContractSignRecord::getContractInfoId, dto.getContractInfoId())
                .eq(ContractSignRecord::getSceneType, dto.getSceneType())
                .eq(ContractSignRecord::getSceneId, dto.getSceneId()));
    }

    @Override
    public ContractSignRecordInfoSDTO info(Long userId, Long contractInfoId, Integer sceneType, Long sceneId) {
        return contractSignRecordMapper.info(userId, contractInfoId, sceneType, sceneId);
    }

    @Override
    public ContractSignRecordInfoSDTO info(Long contractSignRecordId) {
        return contractSignRecordMapper.contractSignInfo(contractSignRecordId);
    }
}
